package com.woniu.shiro_config;

import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.woniu.entity.RbacManager;
import com.woniu.service.RbacManagerService;
import com.woniu.service.RbacPermService;
import com.woniu.service.RbacRoleService;
import com.woniu.utils.JWTUtils;
import com.woniu.utils.MyJsonWebToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import java.util.Set;

/**
 * @author:陈涵
 * @Do:第四步我的jwt自定义域，专门用来处理MyJsonWebToken对象
 * @date: 2022/9/6 16:42
 */
@Configuration
public class MyJWTRealm extends AuthorizingRealm {
    private final String REALMNAME="MyJWTRealm";

    @Autowired(required = false)
    RbacManagerService rbacManagerService;
    @Autowired
    RbacRoleService rbacRoleService;
    @Autowired
    RbacPermService rbacPermService;
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof MyJsonWebToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = principals.getPrimaryPrincipal()+"";
        //访问数据库获取对应的角色set集合
        Set<String> rbacRoles = rbacRoleService.findOneByUserName(username);
        //存放的是角色信息
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(rbacRoles);
        //查询当前登录用户的权限信息
        Set<String> rbacPerms = rbacPermService.findPermBySetRoles(username);
        simpleAuthorizationInfo.setStringPermissions(rbacPerms);
        return simpleAuthorizationInfo;
    }
    /**
     * 认证方法的开发！
     * ChangeLog : 1. 创建 (22/09/06/0006 11:57 [马宇航]);
     * @param authenticationToken
     * @return org.apache.shiro.authc.AuthenticationInfo
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = authenticationToken.getCredentials()+"";
        //解析token拿到用户名
        String username = JWTUtils.getUsername(token);
        if (username==null){
            throw new AuthenticationException("token中无账号！");
        }
        //说明这个username是可以用的，因为token没有过期,如果用户在前端修改了密码！需不需要重新跳回登录页面？
        //上述代码有一个问题，如果密码改了，但是这个token没过期，也就是说，依然是token有效，认证通过的！
        RbacManager rbacManager = rbacManagerService.findOneByName(username);
        try {
            //进行过期校验和防篡改校验, 只有一个结果，如果不是true则直接抛出异常,jwt的校验异常
            JWTUtils.verify(token, rbacManager.getAccount(),rbacManager.getPassword());
        }catch (JWTVerificationException e){
            //转换封装一下，变成认证异常
            throw new AuthenticationException(e.getMessage());
        }
        return new SimpleAuthenticationInfo(username,token,REALMNAME);
    }
}
